package uk.ac.lkl.common.util;



import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;


/**
 * A converter that uses a constructor in the destination class.
 * 
 * In order for this class to be used, class <code>D</code> must define a
 * constructor that takes a single argument of type <code>S</code>.
 * 
 * @author Darren Pearce
 * @version $Revision$
 * @version $Date$
 * 
 */
public class ConstructorBasedConverter<S, D> implements Converter<S, D> {

    /**
     * The constructor to use when the <code>convert()</code> method is
     * called.
     * 
     */
    private Constructor<D> constructor;


    /**
     * Create a new instance for the given source and destination classes.
     * 
     * Explicit references to these classes are required so that reflection can
     * be used to locate the appropriate constructor.
     * 
     * @param sourceClass
     *            the source class
     * @param destinationClass
     *            the destination class
     * 
     * @throw IllegalArgumentException if the destination class does not have a
     *        constructor of the appropriate type
     */
    public ConstructorBasedConverter(Class<S> sourceClass,
            Class<D> destinationClass) {
        try {
            this.constructor = destinationClass.getConstructor(sourceClass);
        }
        catch (NoSuchMethodException e) {
            // do more here so that exception handled nicely
            throw new IllegalArgumentException("Class "
                    + destinationClass.getName() + " must have a "
                    + sourceClass.getName() + " constructor.");
        }
    }


    /**
     * Converts <code>source</code> to an instance of the destination class
     * <code>D</code> using the appropriate constructor in class
     * <code>D</code>.
     * 
     * If any exception occurs when calling the constructor, the method returns
     * <code>null</code>.
     * 
     * @param source
     *            the instance to convert
     * @return an instance of class <code>D</code>; or <code>null</code> if
     *         any exception occurred during the constructor call
     * 
     */
    public D convert(S source) {
        try {
            return constructor.newInstance(source);
        }
        catch (InvocationTargetException e) {
            return null;
        }
        catch (IllegalAccessException e) {
            return null;
        }
        catch (InstantiationException e) {
            return null;
        }
    }

}
